////////////////////////////////////////////////////////////////////////////////
//
//	Original file Name: Entity.java
//	Originating Author: JWhitefield
//	
//	Description: Anything which exists within the game world
//
////////////////////////////////////////////////////////////////////////////////

package com.jjw.game.world.entity.character;

import java.awt.Graphics;
import java.util.Random;

import com.jjw.game.graphics.Sprite;
import com.jjw.game.screen.IRenderable;
import com.jjw.game.screen.Screen;

@SuppressWarnings("unused")
/**
 * Anything which exists within the game world
 * @author JWhitefield
 *
 */
public class Entity implements IRenderable  {
	//--------------------------------------------------------------------------
	//
	//Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	// Public
	//----------------------------------
	
	/**
	 * Random generator helpful for entity
	 */
	protected final Random random = new Random();
	
	/**
	 * The current sprite to be rendered
	 */
	protected Sprite currentSprite = null;
	//----------------------------------
	//  Getters / Setters
	//----------------------------------
	
	/**
	 * Get the x location of the entity
	 * @return
	 */
	public int getX() {
		return x;
	}

	/**
	 * Set the x location of the entity
	 * @param x
	 */
	protected void setX(int x) {
		this.x = x;
	}

	/**
	 * Get the y location of the entity
	 * @return
	 */
	public int getY() {
		return y;
	}

	/**
	 * Get the y location of the entity
	 * @param y
	 */
	protected void setY(int y) {
		this.y = y;
	}

	/**
	 * Get the x rotation of the entity 
	 * @return
	 */
	public int getXr() {
		return xr;
	}

	/**
	 * Set the x rotation of the entity
	 * @param xr
	 */
	protected void setXr(int xr) {
		this.xr = xr;
	}

	/**
	 * Get the y rotation of the entity
	 * @return
	 */
	public int getYr() {
		return yr;
	}

	/**
	 * Get the y rotation of the entity
	 * @param yr
	 */
	protected void setYr(int yr) {
		this.yr = yr;
	}

	/**
	 * Has the entity been removed
	 * @return
	 */
	public boolean isRemoved() {
		return removed;
	}

	/**
	 * Set the removed flag for this item 
	 * @param removed
	 */
	protected void setRemoved(boolean removed) {
		this.removed = removed;
	}
	
	//----------------------------------
	// Private
	//----------------------------------
	
	/**
	 *  X and Y location of the entity
	 */
	private int x, y;
	
	/**
	 * X rotation of the entity 
	 */
	private int xr = 6;
	
	/**
	 * Y rotation of the entity 
	 */
	private int yr = 6;
	
	/**
	 *  Shows if the entity has been removed from the level  
	 */
	private  boolean removed;
	
	//--------------------------------------------------------------------------
	//
	//  Methods
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	// Public
	//----------------------------------
	
	/**
	 * Used to move the entity
	 * 
	 * @param xa the x axis we want to move to 
	 * @param ya the y axis we want to move to
	 *   
	 * @return weather we moved or not
	 */
	public boolean move(int xa, int ya) {
		
		//Check that nether positions are zero
		if (xa != 0 || ya != 0) {
			
			//Flag to show if we are stopped or not
			boolean stopped = true;
			
			//Check to see if we have been stopped or not
			
			//First check on the x axis 
			if (xa != 0 && move2(xa, 0)){
				stopped = false;
			}
			
			//Secondly check on the y axis 
			if (ya != 0 && move2(0, ya)){
				stopped = false;
			}
		}
		
		//Return true to let our caller know we have moved
		return true;
	}
	
	/**
	 * We have a second move function we don't this for collision detection reasons, so that if the two adjacent tiles   
	 * we cannot move to tile 0 as the join between the top left and bottom right are blocking us
	 * 
	 * 1P
	 * 01
	 * 
	 * @param xa
	 * @param ya
	 * @return
	 */
	protected boolean move2(int xa, int ya) {
		
		//If both of these values have been set we need to throw an error
		if (xa != 0 && ya != 0){
			
			//We can't move on two axis at once so throw an exception i this shouln't happen 
			throw new IllegalArgumentException("Entity: Move Two Function cannot be called with both xa and xy axis at once");
		}

		//Shift the xto and yto 4 bits 
		int xto0 = ((this.x) - this.xr) >> 4;
		int yto0 = ((this.y) - this.yr) >> 4;
		int xto1 = ((this.x) + this.xr) >> 4;
		int yto1 = ((this.y) + this.yr) >> 4;

		//Shift the xto and yto 4 bits 
		int xt0 = ((this.x + xa) - this.xr) >> 4;
		int yt0 = ((this.y + ya) - this.yr) >> 4;
		int xt1 = ((this.x + xa) + this.xr) >> 4;
		int yt1 = ((this.y + ya) + this.yr) >> 4;

		//Set the x and y of the entity
		this.x += xa;
		this.y += ya;
		
		//Return true as we have moved the entity
		return true;
	}
	
	/**
	 * Shows if the entity has been removed from the level  
	 */
	public void remove() {
		//Set removed to true
		this.setRemoved( true );
	}
	
	//----------------------------------
	// Private
	//----------------------------------
	
	//----------------------------------
	// Overridden / Implemented
	//----------------------------------
		
	/**
	 * Ticks the entity 
	 */
	public void tick(){
		
	}

	@Override
	public void render(Screen screen, int x, int y) {
	
		//We are unable to draw an null sprite, or a null screen
		if(this.currentSprite == null || screen == null)
			return;
		
		
		//Render the current sprite
		screen.render(x,y, this.currentSprite);
	}
	
	/**
	 * Calls the other render function using the entity own x and y values 
	 */
	public void render( Screen screen ) {
		
		//Render the entity to the screen 
		this.render(screen, this.getX(), this.getY());
	}
}
